using System;
using System.Xml.XPath;
using CriticalSystems.Instrumentation.Configuration;
using CriticalSystems.Instrumentation.Internal;
using log4net;

namespace CriticalSystems.Instrumentation.TraceWriters
{
    public class Log4NetTraceWriterFactory : ITraceWriterFactory
    {
        #region ITraceWriterFactory Members
        /// <summary>
        /// Creates the trace writer using the supplied XML settings.
        /// </summary>
        /// <param name="fullTypeName">Full name of the type.</param>
        /// <param name="settings">The configuration settings.</param>
        /// <returns></returns>
        public ITraceWriter Create(string fullTypeName, IXPathNavigable settings)
        {
            return new Log4NetTraceWriter(fullTypeName);
        }
        #endregion
    }

    internal class Log4NetTraceWriter : ITraceWriter
    {
        private readonly string fullTypeName;
        private readonly ILog logger;

        public Log4NetTraceWriter(string fullTypeName)
        {
            this.fullTypeName = fullTypeName;
            this.logger = LogManager.GetLogger(this.fullTypeName);
        }

        #region ITraceWriter Members
        public TracingFlags Flags
        {
            get
            {
                TracingFlags flags = 0;
                if (this.logger.IsInfoEnabled)
                {
                    flags |= TracingFlags.TraceInfo;
                }
                if (this.logger.IsDebugEnabled)
                {
                    if ((InstrumentationConfiguration.Instance.Tracing & TracingFlags.TraceEntryExitValues) != 0)
                    {
                        flags |= TracingFlags.TraceEntryExitValues;
                    }
                    else
                    {
                        flags |= TracingFlags.TraceEntryExit;
                    }
                }
                if (this.logger.IsWarnEnabled)
                {
                    flags |= TracingFlags.TraceWarning;
                }
                if (this.logger.IsErrorEnabled || this.logger.IsFatalEnabled)
                {
                    flags |= TracingFlags.TraceError;
                }
                return flags;
            }
        }

        public void Write(TraceType traceType, int indent, string instance, string type, string method, string text)
        {
            log4net.GlobalContext.Properties["instance"] = Logging.Instance;
            string message;
            if (text == null)
            {
                message = string.Format("{0} {1} {2}", SimpleTraceWriterWrapper.GetTracePrefix(traceType),
                                               SimpleTraceWriterWrapper.GetIndentString(indent, '.'),
                                               method);
            }
            else
            {
                message = string.Format("{0} {1} {2} : {3}", SimpleTraceWriterWrapper.GetTracePrefix(traceType),
                                               SimpleTraceWriterWrapper.GetIndentString(indent, '.'),
                                               method, text);
            }
            switch (traceType)
            {
                case TraceType.In:
                    this.logger.Debug(message);
                    break;
                case TraceType.Out:
                    this.logger.Debug(message);
                    break;
                case TraceType.Info:
                    this.logger.Info(message);
                    break;
                case TraceType.Error:
                    this.logger.Error(message);
                    break;
                case TraceType.Warning:
                    this.logger.Warn(message);
                    break;
            }
        }

        public void Write(string text)
        {
            throw new NotImplementedException();
        }

        public bool SimpleWriter
        {
            get { return false; }
        }
        #endregion
    }
}